<?php

require_once 'vendor/autoload.php';

use Smalot\Cups\Builder\Builder;
use Smalot\Cups\Manager\JobManager;
use Smalot\Cups\Manager\PrinterManager;
use Smalot\Cups\Model\Job;
use Smalot\Cups\Transport\Client;
use Smalot\Cups\Transport\ImprovedClient;
use Smalot\Cups\Transport\ResponseParser;
use Http\Client\Socket\Client as SocketHttpClient;
use Http\Factory\Guzzle\RequestFactory;
use Http\Factory\Guzzle\StreamFactory;
use Http\Factory\Guzzle\UriFactory;
use Http\Factory\Guzzle\ResponseFactory;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;

/**
 * IPP 打印调试工具
 * 专门用于调试和修复IPP连接问题
 */
class IPPDebugTool
{
    private string $printerIP;
    private int $printerPort;
    private array $debugResults = [];
    
    public function __construct(string $printerIP = '10.1.0.12', int $printerPort = 631)
    {
        $this->printerIP = $printerIP;
        $this->printerPort = $printerPort;
    }
    
    /**
     * 运行完整的IPP调试流程
     */
    public function runFullDebug(): void
    {
        echo "🔧 IPP 打印调试工具\n";
        echo "目标打印机: {$this->printerIP}:{$this->printerPort}\n";
        echo str_repeat('=', 60) . "\n\n";
        
        // 1. 基础网络测试
        $this->testBasicNetwork();
        
        // 2. IPP协议测试
        $this->testIPPProtocol();
        
        // 3. 详细连接调试
        $this->debugDetailedConnection();
        
        // 4. 尝试不同的IPP方法
        $this->tryDifferentIPPMethods();
        
        // 5. 生成调试报告
        $this->generateDebugReport();
    }
    
    /**
     * 基础网络测试
     */
    private function testBasicNetwork(): void
    {
        echo "🌐 步骤1: 基础网络测试\n";
        echo str_repeat('-', 40) . "\n";
        
        // Ping测试
        $pingResult = $this->pingTest();
        echo "1. Ping测试: " . ($pingResult ? "✅ 成功" : "❌ 失败") . "\n";
        $this->debugResults['ping'] = $pingResult;
        
        // 端口测试
        $portResult = $this->portTest();
        echo "2. 端口631测试: " . ($portResult ? "✅ 开放" : "❌ 关闭") . "\n";
        $this->debugResults['port'] = $portResult;
        
        // HTTP连接测试
        $httpResult = $this->httpTest();
        echo "3. HTTP连接测试: " . ($httpResult ? "✅ 可访问" : "❌ 不可访问") . "\n";
        $this->debugResults['http'] = $httpResult;
        
        echo "\n";
    }
    
    /**
     * IPP协议测试
     */
    private function testIPPProtocol(): void
    {
        echo "📡 步骤2: IPP协议测试\n";
        echo str_repeat('-', 40) . "\n";
        
        // 测试IPP Get-Printer-Attributes请求
        $ippResult = $this->testIPPGetPrinterAttributes();
        echo "1. IPP Get-Printer-Attributes: " . ($ippResult['success'] ? "✅ 成功" : "❌ 失败") . "\n";
        if (!$ippResult['success']) {
            echo "   错误: {$ippResult['error']}\n";
        }
        $this->debugResults['ipp_get_attributes'] = $ippResult;
        
        // 测试IPP Get-Jobs请求
        $jobsResult = $this->testIPPGetJobs();
        echo "2. IPP Get-Jobs: " . ($jobsResult['success'] ? "✅ 成功" : "❌ 失败") . "\n";
        if (!$jobsResult['success']) {
            echo "   错误: {$jobsResult['error']}\n";
        }
        $this->debugResults['ipp_get_jobs'] = $jobsResult;
        
        echo "\n";
    }
    
    /**
     * 详细连接调试
     */
    private function debugDetailedConnection(): void
    {
        echo "🔍 步骤3: 详细连接调试\n";
        echo str_repeat('-', 40) . "\n";
        
        // 测试不同的超时设置
        $timeouts = [5, 10, 30, 60];
        foreach ($timeouts as $timeout) {
            $result = $this->testConnectionWithTimeout($timeout);
            echo "1. 超时{$timeout}秒测试: " . ($result ? "✅ 成功" : "❌ 失败") . "\n";
            $this->debugResults["timeout_{$timeout}"] = $result;
        }
        
        // 测试不同的socket选项
        $socketResult = $this->testSocketOptions();
        echo "2. Socket选项测试: " . ($socketResult ? "✅ 成功" : "❌ 失败") . "\n";
        $this->debugResults['socket_options'] = $socketResult;
        
        echo "\n";
    }
    
    /**
     * 尝试不同的IPP方法
     */
    private function tryDifferentIPPMethods(): void
    {
        echo "🛠️ 步骤4: 尝试不同的IPP方法\n";
        echo str_repeat('-', 40) . "\n";
        
        // 方法1: 标准CUPS客户端
        $method1 = $this->tryStandardCupsClient();
        echo "1. 标准CUPS客户端: " . ($method1 ? "✅ 成功" : "❌ 失败") . "\n";
        
        // 方法2: 改进的客户端
        $method2 = $this->tryImprovedClient();
        echo "2. 改进的客户端: " . ($method2 ? "✅ 成功" : "❌ 失败") . "\n";
        
        // 方法3: 原始HTTP请求
        $method3 = $this->tryRawHTTPRequest();
        echo "3. 原始HTTP请求: " . ($method3 ? "✅ 成功" : "❌ 失败") . "\n";
        
        // 方法4: cURL请求
        $method4 = $this->tryCurlRequest();
        echo "4. cURL请求: " . ($method4 ? "✅ 成功" : "❌ 失败") . "\n";
        
        $this->debugResults['methods'] = [
            'standard_cups' => $method1,
            'improved_client' => $method2,
            'raw_http' => $method3,
            'curl' => $method4
        ];
        
        echo "\n";
    }
    
    /**
     * Ping测试
     */
    private function pingTest(): bool
    {
        $command = "ping -n 1 -w 1000 {$this->printerIP}";
        $output = [];
        $returnCode = 0;
        exec($command . ' 2>&1', $output, $returnCode);
        return $returnCode === 0;
    }
    
    /**
     * 端口测试
     */
    private function portTest(): bool
    {
        $connection = @fsockopen($this->printerIP, $this->printerPort, $errno, $errstr, 5);
        if ($connection) {
            fclose($connection);
            return true;
        }
        return false;
    }
    
    /**
     * HTTP测试
     */
    private function httpTest(): bool
    {
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'timeout' => 10,
                'header' => "Host: {$this->printerIP}:{$this->printerPort}\r\n"
            ]
        ]);
        
        $result = @file_get_contents("http://{$this->printerIP}:{$this->printerPort}/", false, $context);
        return $result !== false;
    }
    
    /**
     * 测试IPP Get-Printer-Attributes请求
     */
    private function testIPPGetPrinterAttributes(): array
    {
        try {
            // 创建IPP请求数据
            $ippData = $this->createIPPGetPrinterAttributesRequest();
            
            $context = stream_context_create([
                'http' => [
                    'method' => 'POST',
                    'header' => [
                        "Content-Type: application/ipp",
                        "Host: {$this->printerIP}:{$this->printerPort}",
                        "User-Agent: CUPS-IPP-Debug/1.0",
                        "Accept: application/ipp"
                    ],
                    'content' => $ippData,
                    'timeout' => 30
                ]
            ]);
            
            $response = @file_get_contents(
                "http://{$this->printerIP}:{$this->printerPort}/ipp/print",
                false,
                $context
            );
            
            if ($response !== false) {
                return ['success' => true, 'response_length' => strlen($response)];
            } else {
                $error = error_get_last();
                return ['success' => false, 'error' => $error['message'] ?? 'Unknown error'];
            }
            
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    /**
     * 测试IPP Get-Jobs请求
     */
    private function testIPPGetJobs(): array
    {
        try {
            // 创建IPP请求数据
            $ippData = $this->createIPPGetJobsRequest();
            
            $context = stream_context_create([
                'http' => [
                    'method' => 'POST',
                    'header' => [
                        "Content-Type: application/ipp",
                        "Host: {$this->printerIP}:{$this->printerPort}",
                        "User-Agent: CUPS-IPP-Debug/1.0",
                        "Accept: application/ipp"
                    ],
                    'content' => $ippData,
                    'timeout' => 30
                ]
            ]);
            
            $response = @file_get_contents(
                "http://{$this->printerIP}:{$this->printerPort}/ipp/print",
                false,
                $context
            );
            
            if ($response !== false) {
                return ['success' => true, 'response_length' => strlen($response)];
            } else {
                $error = error_get_last();
                return ['success' => false, 'error' => $error['message'] ?? 'Unknown error'];
            }
            
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    /**
     * 测试不同超时设置的连接
     */
    private function testConnectionWithTimeout(int $timeout): bool
    {
        $connection = @fsockopen($this->printerIP, $this->printerPort, $errno, $errstr, $timeout);
        if ($connection) {
            fclose($connection);
            return true;
        }
        return false;
    }
    
    /**
     * 测试Socket选项
     */
    private function testSocketOptions(): bool
    {
        $context = stream_context_create([
            'socket' => [
                'so_reuseport' => true,
                'so_keepalive' => true,
                'tcp_nodelay' => true
            ]
        ]);
        
        $socket = @stream_socket_client(
            "tcp://{$this->printerIP}:{$this->printerPort}",
            $errno,
            $errstr,
            30,
            STREAM_CLIENT_CONNECT,
            $context
        );
        
        if ($socket) {
            fclose($socket);
            return true;
        }
        return false;
    }
    
    /**
     * 尝试标准CUPS客户端
     */
    private function tryStandardCupsClient(): bool
    {
        try {
            $builder = new Builder();
            $client = new Client();
            $responseParser = new ResponseParser();
            $printerManager = new PrinterManager($builder, $client, $responseParser);
            
            $printer = $printerManager->findByUri("ipp://{$this->printerIP}:{$this->printerPort}/ipp/print");
            return $printer !== null;
            
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * 尝试改进的客户端
     */
    private function tryImprovedClient(): bool
    {
        try {
            $client = ImprovedClient::createForIpAddress($this->printerIP, $this->printerPort);
            $builder = new Builder();
            $printerManager = new PrinterManager($builder, $client);
            
            $printer = $printerManager->findByUri("ipp://{$this->printerIP}:{$this->printerPort}/ipp/print");
            return $printer !== null;
            
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * 尝试原始HTTP请求
     */
    private function tryRawHTTPRequest(): bool
    {
        $ippData = $this->createIPPGetPrinterAttributesRequest();
        
        $context = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => [
                    "Content-Type: application/ipp",
                    "Host: {$this->printerIP}:{$this->printerPort}",
                    "Content-Length: " . strlen($ippData)
                ],
                'content' => $ippData,
                'timeout' => 30
            ]
        ]);
        
        $response = @file_get_contents(
            "http://{$this->printerIP}:{$this->printerPort}/ipp/print",
            false,
            $context
        );
        
        return $response !== false;
    }
    
    /**
     * 尝试cURL请求
     */
    private function tryCurlRequest(): bool
    {
        if (!function_exists('curl_init')) {
            return false;
        }
        
        $ippData = $this->createIPPGetPrinterAttributesRequest();
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => "http://{$this->printerIP}:{$this->printerPort}/ipp/print",
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $ippData,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/ipp',
                "Host: {$this->printerIP}:{$this->printerPort}",
                'User-Agent: CUPS-IPP-Debug/1.0'
            ],
            CURLOPT_TIMEOUT => 30,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => false
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return $response !== false && $httpCode < 400;
    }
    
    /**
     * 创建IPP Get-Printer-Attributes请求
     */
    private function createIPPGetPrinterAttributesRequest(): string
    {
        // IPP版本 (2.0)
        $data = "\x02\x00";
        
        // 操作ID (Get-Printer-Attributes = 0x000B)
        $data .= "\x00\x0B";
        
        // 请求ID (随机)
        $data .= "\x00\x00\x00\x01";
        
        // 操作属性标签
        $data .= "\x01";
        
        // attributes-charset
        $data .= "\x47\x00\x12attributes-charset\x00\x05utf-8";
        
        // attributes-natural-language
        $data .= "\x48\x00\x1Battributes-natural-language\x00\x02en";
        
        // printer-uri
        $printerUri = "ipp://{$this->printerIP}:{$this->printerPort}/ipp/print";
        $data .= "\x45\x00\x0Bprinter-uri" . pack('n', strlen($printerUri)) . $printerUri;
        
        // 结束标签
        $data .= "\x03";
        
        return $data;
    }
    
    /**
     * 创建IPP Get-Jobs请求
     */
    private function createIPPGetJobsRequest(): string
    {
        // IPP版本 (2.0)
        $data = "\x02\x00";
        
        // 操作ID (Get-Jobs = 0x000A)
        $data .= "\x00\x0A";
        
        // 请求ID (随机)
        $data .= "\x00\x00\x00\x02";
        
        // 操作属性标签
        $data .= "\x01";
        
        // attributes-charset
        $data .= "\x47\x00\x12attributes-charset\x00\x05utf-8";
        
        // attributes-natural-language
        $data .= "\x48\x00\x1Battributes-natural-language\x00\x02en";
        
        // printer-uri
        $printerUri = "ipp://{$this->printerIP}:{$this->printerPort}/ipp/print";
        $data .= "\x45\x00\x0Bprinter-uri" . pack('n', strlen($printerUri)) . $printerUri;
        
        // 结束标签
        $data .= "\x03";
        
        return $data;
    }
    
    /**
     * 生成调试报告
     */
    private function generateDebugReport(): void
    {
        echo "📊 调试报告\n";
        echo str_repeat('=', 60) . "\n";
        
        echo "\n🌐 网络连接状态:\n";
        echo "   Ping: " . ($this->debugResults['ping'] ? "✅ 正常" : "❌ 失败") . "\n";
        echo "   端口631: " . ($this->debugResults['port'] ? "✅ 开放" : "❌ 关闭") . "\n";
        echo "   HTTP服务: " . ($this->debugResults['http'] ? "✅ 可访问" : "❌ 不可访问") . "\n";
        
        echo "\n📡 IPP协议测试:\n";
        $ippGetAttr = $this->debugResults['ipp_get_attributes'];
        echo "   Get-Printer-Attributes: " . ($ippGetAttr['success'] ? "✅ 成功" : "❌ 失败") . "\n";
        if (!$ippGetAttr['success']) {
            echo "      错误: {$ippGetAttr['error']}\n";
        }
        
        $ippGetJobs = $this->debugResults['ipp_get_jobs'];
        echo "   Get-Jobs: " . ($ippGetJobs['success'] ? "✅ 成功" : "❌ 失败") . "\n";
        if (!$ippGetJobs['success']) {
            echo "      错误: {$ippGetJobs['error']}\n";
        }
        
        echo "\n🛠️ 连接方法测试:\n";
        $methods = $this->debugResults['methods'];
        echo "   标准CUPS客户端: " . ($methods['standard_cups'] ? "✅ 成功" : "❌ 失败") . "\n";
        echo "   改进的客户端: " . ($methods['improved_client'] ? "✅ 成功" : "❌ 失败") . "\n";
        echo "   原始HTTP请求: " . ($methods['raw_http'] ? "✅ 成功" : "❌ 失败") . "\n";
        echo "   cURL请求: " . ($methods['curl'] ? "✅ 成功" : "❌ 失败") . "\n";
        
        echo "\n💡 建议:\n";
        $this->generateRecommendations();
    }
    
    /**
     * 生成建议
     */
    private function generateRecommendations(): void
    {
        $recommendations = [];
        
        if (!$this->debugResults['ping']) {
            $recommendations[] = "检查网络连接和IP地址配置";
        }
        
        if (!$this->debugResults['port']) {
            $recommendations[] = "检查打印机IPP服务是否启用";
            $recommendations[] = "检查防火墙设置，确保端口631开放";
        }
        
        if (!$this->debugResults['http']) {
            $recommendations[] = "打印机可能不支持HTTP访问，但IPP可能仍然可用";
        }
        
        $ippGetAttr = $this->debugResults['ipp_get_attributes'];
        if (!$ippGetAttr['success']) {
            if (strpos($ippGetAttr['error'], 'timeout') !== false) {
                $recommendations[] = "增加连接超时时间";
                $recommendations[] = "检查打印机是否处于节能模式";
            }
            if (strpos($ippGetAttr['error'], 'refused') !== false) {
                $recommendations[] = "打印机可能拒绝IPP连接，检查IPP设置";
            }
        }
        
        $methods = $this->debugResults['methods'];
        if (!$methods['standard_cups'] && !$methods['improved_client']) {
            $recommendations[] = "考虑使用原始HTTP请求或cURL作为备用方案";
        }
        
        if (empty($recommendations)) {
            $recommendations[] = "所有测试都通过，IPP打印应该可以正常工作";
        }
        
        foreach ($recommendations as $i => $recommendation) {
            echo "   " . ($i + 1) . ". {$recommendation}\n";
        }
    }
}

// 运行调试工具
try {
    $debugTool = new IPPDebugTool('10.1.0.12', 631);
    $debugTool->runFullDebug();
    
} catch (Exception $e) {
    echo "❌ 调试工具执行失败\n";
    echo "错误信息: " . $e->getMessage() . "\n";
    echo "错误文件: " . $e->getFile() . ":" . $e->getLine() . "\n";
}

echo "\n🔧 调试完成！\n";